use serde::{Deserialize,Serialize};
use std::cmp::Ordering;


#[derive(Debug, Serialize, Deserialize)]
pub struct SystemInfo {
    platform: Platform,
    net: Vec<Net>,
    memory: Memory,
    disk: Vec<Disk>,
    cpu: Cpu,
    process:Vec<Process>
}

#[derive(Debug, Serialize, Deserialize)]
struct Process{
    pid:String,
    name:String
}

#[derive(Debug, Serialize, Deserialize)]
struct Platform {
    system: String,
    hostname: String,
    version: String,
    arch: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct Net {
    name: String,
    mac: String
}

impl Eq for Net {}

impl PartialEq<Self> for Net {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}

impl PartialOrd<Self> for Net {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Net {
    fn cmp(&self, other: &Self) -> Ordering {
        self.name.to_uppercase().cmp(&other.name.to_uppercase())
    }
}

#[derive(Debug, Serialize, Deserialize)]
struct Memory {
    total: u64,
    available: u64,
    free: u64,
}

#[derive(Debug, Serialize, Deserialize)]
struct Disk {
    name: String,
    kind: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct Cpu {
    count: usize,
    usage: f32,
}
use sysinfo::{
    Disks, Networks, System
};

pub fn get_sys_info() -> Result<SystemInfo,String> {
    let mut sys = System::new_all();
    sys.refresh_all();
    let memory:Memory = Memory{
        total: sys.total_memory(),
        available: sys.total_swap(),
        free: sys.used_swap(),
    };
    let platform = Platform {
        system: System::name().unwrap(),
        hostname: System::kernel_version().unwrap(),
        version: System::os_version().unwrap(),
        arch: System::host_name().unwrap(),
    };
    let mut disk_list: Vec<Disk> = Vec::new();
    let disks = Disks::new_with_refreshed_list();
    for disk in disks.list() {
        disk_list.push(Disk{
            name: format!("{:?}",disk.name()),
            kind: format!("{:?}",disk.kind())
        })
    }
    let mut cpu_usages: Vec<f32> = Vec::new();
    for cpu in sys.cpus() {
        cpu_usages.push(cpu.cpu_usage());
    }
    let cpu_usage_sum: f32 = cpu_usages.iter().sum();
    
    let average = cpu_usage_sum as f32 / cpu_usages.len() as f32;
    let cpu = Cpu { 
        count: sys.cpus().len(), 
        usage: average
    };
    let mut process_list: Vec<Process> = Vec::new();
    for (pid, process) in sys.processes() {
        //println!("[{pid}] {} {:?}", process.name(), process.disk_usage());
        process_list.push(Process{
            pid: pid.to_string(),
            name: process.name().to_string()
        })
    }
    let networks = Networks::new_with_refreshed_list();
    let mut network_list: Vec<Net> = Vec::new();
    for (interface_name, network) in &networks {
        //println!("[{interface_name}]: {network:?}");
        network_list.push(Net{
            name:interface_name.to_string(),
            mac:network.mac_address().to_string()
        })
    }
    let res_system_info = SystemInfo{
        platform: platform,
        net: network_list,
        memory: memory,
        disk: disk_list,
        cpu: cpu,
        process:process_list
    };
    Ok(res_system_info)
    //let res = serde_json::to_string(&res_system_info).unwrap();
     
}

